package com.gallop.mq;

import com.gallop.mq.core.MQExecutorProvider;
import com.gallop.mq.core.MQMessageCodec;
import com.gallop.mq.core.MQMessageDispatcher;
import com.gallop.mq.core.exception.MQException;
import com.gallop.mq.core.template.handler.registry.MessageDeliveryHandlerRegistry;

import java.time.Duration;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * MQ消息发送实体。
 * <p>
 * 可通过{@link org.springframework.beans.factory.annotation.Autowired}注入
 */
public interface MQTemplate {

    /**
     * 初始化操作
     *
     * @param properties       MQ配置
     * @param dispatcher       消息监听分发
     * @param codec            消息编解码器
     * @param executorProvider MQ工作线程池provider
     * @param handlerRegistry  可选参数，统一管理MQ消息收发逻辑
     * @throws MQException 异常情况抛出，会中断初始化及启动流程
     */
    void init(MQProperties properties,
              MQMessageDispatcher dispatcher,
              MQMessageCodec codec,
              MQExecutorProvider executorProvider,
              MessageDeliveryHandlerRegistry handlerRegistry) throws MQException;

    default void onDispose() {
    }

    MQMessageCodec getCodec();

    void setCodec(MQMessageCodec codec);

    MQMessageDispatcher getDispatcher();

    void setDispatcher(MQMessageDispatcher dispatcher);

    /**
     * 向MQ发送一条消息
     *
     * @param message 消息内容
     * @param topic   发送地址
     */
    void send(Object message, String topic);


    /**
     * 向MQ发送一条rpc请求，并异步处理响应。
     *
     * @param <P>        响应内容，rpc调用失败返回null
     * @param message    请求消息内容
     * @param topic      请求地址
     * @param onResponse 响应回调
     */
    default <P> void request(Object message, String topic, Consumer<P> onResponse) {
        request(message, topic, null, onResponse);
    }

    /**
     * 向MQ发送一条rpc请求，并异步处理响应。
     *
     * @param <P>            响应内容，rpc调用失败返回null
     * @param message        请求消息内容
     * @param topic          请求地址
     * @param requestTimeout 自定义超时，为null时使用缺省配置超时时间
     * @param onResponse     响应回调
     */
    <P> void request(Object message, String topic, Duration requestTimeout, Consumer<P> onResponse);

    /**
     * 向MQ发送一条rpc请求，并异步处理响应。
     *
     * @param <P>        响应内容，rpc调用失败返回null
     * @param message    请求消息内容
     * @param topic      请求地址
     * @param onResponse 响应成功回调
     * @param onError    调用失败回调
     */
    default <P> void request(Object message, String topic, Consumer<P> onResponse, BiConsumer<Object, Exception> onError) {
        request(message, topic, null, onResponse, onError);
    }

    /**
     * 向MQ发送一条rpc请求，并异步处理响应。
     *
     * @param <P>            响应内容，rpc调用失败返回null
     * @param message        请求消息内容
     * @param topic          请求地址
     * @param requestTimeout 自定义超时，为null时使用缺省配置超时时间
     * @param onResponse     响应成功回调
     * @param onError        调用失败回调
     */
    <P> void request(Object message, String topic, Duration requestTimeout, Consumer<P> onResponse, BiConsumer<Object, Exception> onError);

    /**
     * 向MQ发送一条rpc请求，并同步获得响应结果
     *
     * @param message 请求消息内容
     * @param topic   请求地址
     * @param <P>     响应内容类型
     * @return 响应内容，rpc调用失败返回null
     * @throws InterruptedException 请求线程被中断后抛出异常
     */
    default <P> P request(Object message, String topic) throws InterruptedException {
        return request(message, topic, (Duration) null);
    }

    /**
     * 向MQ发送一条rpc请求，并同步获得响应结果
     *
     * @param message        请求消息内容
     * @param topic          请求地址
     * @param <P>            响应内容类型
     * @param receiveTimeout 自定义超时，为空使用默认设置
     * @return 响应内容，rpc调用失败返回null
     * @throws InterruptedException 请求线程被中断后抛出异常
     */
    <P> P request(Object message, String topic, Duration receiveTimeout) throws InterruptedException;
}
